package com.vita.bduck.logger;

import android.os.Environment;
import android.os.StatFs;
import android.text.TextUtils;
import com.alibaba.fastjson.JSON;
import com.vita.bduck.common.FileUtils;

import java.io.*;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: Vita Hao
 * Date: 13-6-19
 * Time: 上午10:10
 * To change this template use File | Settings | File Templates.
 */
public class LogWritter {

    private static final String TAG = "LogWritter";

    private Object lockMe = null;
    private static LogWritter mInstance = new LogWritter();

    private final long MAX_LOGSIZE = LogCrashHandler.maxLogSize; 	// 大于20m删除
    private static final long KEEP_SIZE = 2 * 1024 * 1024; 		// 2m

    /**
     * 单例
     */
    private LogWritter() {
        lockMe = new Object();
    }

    /**
     * 返回单例
     * @return
     */
    public static LogWritter getInstance() {
        return mInstance;
    }

    /**
     * 写入Log信息
     * @param mLogPath Log文件路径
     * @param logType Log类型
     * @param level Log等级
     * @param Tag Log的Tag信息
     * @param logMessage Log信息
     */
    public void toLog(String mLogPath, String level, String Tag, String logMessage) {
        LogInfo logInfo = new LogInfo(LogInfo.TYPE_LOG, level, getTimestamp(),
                Wrap(String.valueOf( Thread.currentThread().getId())), Tag, logMessage);
        toLog(mLogPath, logInfo);
    }

    /**
     * 写入Log信息
     * @param mLogPath Log文件路径
     * @param logType Log类型
     * @param level Log等级
     * @param logMessage Log信息
     */
    public void toLog(String mLogPath, String level, String logMessage) {
        toLog(mLogPath, level, "", logMessage);
    }

    /**
     * 写入操作日志信息
     * @param mLogPath
     * @param functionCode
     * @param remark
     */
    public void toOperationLog(String mLogPath, String functionCode, String remark) {
        LogInfo logInfo = new LogInfo(LogInfo.TYPE_OPERATION_LOG, getTimestamp(),
                functionCode, remark);
        toLog(mLogPath, logInfo);
    }

    /**
     * 写入到日志文件
     * @param mLogPath
     * @param logInfo
     */
    private void toLog(final String mLogPath, final LogInfo logInfo) {
        if (!TextUtils.isEmpty(mLogPath) && logInfo != null) {
            final String logMessage = JSON.toJSONString(logInfo);
            final String fileName = LogConstant.LOG_TAG + getFileNameByTime();
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (lockMe) {
                        try {
                            File logFile = new File(mLogPath);
                            // 不存在就不写
                            if (logFile.exists()) {
                                // 判断大小.大于MAX_LOGSIZE则删除,或者空间不够
                                if (logFile.length() >= MAX_LOGSIZE
                                        || (Log.existSDCard() && logFile
                                        .length() >= getAvailaleSize()
                                        - KEEP_SIZE)) {
                                    FileUtils.deleteFile(logFile.getPath());
                                }

                                PrintWriter pw = new PrintWriter(new FileWriter(
                                        logFile.getPath() + File.separator +fileName, true));
                                pw.println(logMessage);
                                pw.flush();
                                pw.close();
                            }

                        } catch (IOException e) {
                            android.util.Log.e(TAG + "->toLog", e.toString());
                        }
                    } // of synchronized
                } // of run()
            }); // of new Runnable()
            t.start();
        }
    }

    /**
     * 获取log文件中的log信息列表
     * @param mLogPath
     * @param maxLine 最大记录数
     * @param outList 列表引用(先new一个列表传入)
     * @return 读取的数量
     */
    public int getLogInfoes(final String mLogPath, int maxLine, List<LogInfo> outList) {
        if (maxLine == 0) {
            return 0;
        }
        if (TextUtils.isEmpty(mLogPath)) {
            return 0;
        }
        int l = 0;
        synchronized (lockMe) {
            try {
                // 读取文件夹中log文件
                File logFileDir = new File(mLogPath);
                if (logFileDir != null && logFileDir.exists()) {
                    File[] listFile = logFileDir.listFiles();
                    if (listFile != null && listFile.length > 0) {
                        Arrays.sort(listFile, new Comparator<File>() {
                            @Override
                            public int compare(File lhs, File rhs) {
                                return lhs.getName().compareTo(rhs.getName());
                            }
                        });

                        for (File file : listFile) {
                            BufferedReader br = new BufferedReader(new FileReader(file));
                            String line = null;
                            if (outList == null) {
                                break;
                            } else {
                                outList.clear();
                            }
                            while ((line = br.readLine()) != null && l < maxLine) {
                                l++;
                                LogInfo i = JSON.parseObject(line, LogInfo.class);
                                outList.add(i);
                            }
                            br.close();

                            if (l >= maxLine) {
                                break;
                            }
                        }
                    }
                }
            } catch (IOException e) {
                android.util.Log.e(TAG + "->toLog", e.toString());
            }
        } // of synchronized
        return l;
    }

    /**
     * 删除日志中头多少条记录
     * @param mLogPath
     * @param lineCount
     * @return
     */
    public int deleteLog(final String mLogPath, int lineCount) {
        if (lineCount == 0) {
            return 0;
        }
        if (TextUtils.isEmpty(mLogPath)) {
            return 0;
        }
        int l = 0;
        synchronized (lockMe) {
            try {
                // 读取文件夹中log文件
                File logFileDir = new File(mLogPath);
                if (logFileDir != null && logFileDir.exists()) {
                    File[] listFile = logFileDir.listFiles();
                    if (listFile != null && listFile.length > 0) {
                        Arrays.sort(listFile, new Comparator<File>() {
                            @Override
                            public int compare(File lhs, File rhs) {
                                return lhs.getName().compareTo(rhs.getName());
                            }
                        });

                        // 为了防止在遍历中删除文件导致删除不成功，新建需要删除的文件的列表
                        List<File> toDelete = new ArrayList<File>();
                        for (File file : listFile) {
                            BufferedReader br = new BufferedReader(new FileReader(file));
                            int thisDeleteLine = 0;	// 此文件需要删除的行数
                            int thisFileLine = 0;	// 此文件的总行数
                            while (br.readLine() != null) {
                                // 如果小于要删除的条数，本文件需要删除的行数+1
                                if ((l + thisDeleteLine) < lineCount) {
                                    thisDeleteLine++;
                                }
                                thisFileLine++;
                            }
                            br.close();

                            // 如果要删除的与文件长度一样，则直接删除文件
                            if (thisDeleteLine == thisFileLine) {
                                toDelete.add(file);
                            } else {	// 只删除文件中的某些行
                                deleteFileLine(file, thisDeleteLine);
                            }

                            l += thisDeleteLine;

                            if (l >= lineCount) {
                                break;
                            }
                        }
                        // 删除需要删除的文件
                        for (File f : toDelete) {
                            f.delete();
                        }
                    }
                }
            } catch (IOException e) {
                android.util.Log.e(TAG + "->toLog", e.toString());
            }
        }
        return l;
    }

    /**
     * 删除文件中的前多少行
     * @param file
     * @param line
     */
    private void deleteFileLine(File file, int line) {
        int num = 0;
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String str = null;
            List<String> list = new ArrayList<String>();
            while ((str = br.readLine()) != null) {
                ++num;
                if (num <= line) {
                    continue;
                }
                list.add(str);
            }
            br.close();
            BufferedWriter bw = new BufferedWriter(new FileWriter(file));
            for (int i = 0; i < list.size(); i++) {
                bw.write(list.get(i).toString());
                bw.newLine();
            }
            bw.flush();
            bw.close();
        } catch (IOException e) {
            android.util.Log.e(TAG + "->toLog", e.toString());
        }
    }

    /**
     * 获取时间戳
     * @return
     */
    private String getTimestamp() {
        Calendar now = Calendar.getInstance();
        int day = now.get(Calendar.DAY_OF_MONTH);
        int month = now.get(Calendar.MONTH) - Calendar.JANUARY + 1;
        int year = now.get(Calendar.YEAR);
        int hour = now.get(Calendar.HOUR_OF_DAY);
        int minute = now.get(Calendar.MINUTE);
        int second = now.get(Calendar.SECOND);

        return year + "-" + month + "-" + day + " " + hour + ":" + minute
                + ":" + second;
    }

    /**
     * 获取Log文件名
     * @return
     */
    private String getFileNameByTime() {
        Calendar now = Calendar.getInstance();
        int day = now.get(Calendar.DAY_OF_MONTH);
        int month = now.get(Calendar.MONTH) - Calendar.JANUARY + 1;
        int year = now.get(Calendar.YEAR);

        return year + "-" + month + "-" + day + ".log";
    }

    /**
     * 包装[]
     * @param string
     * @return
     */
    private String Wrap(String string) {
        return "[" + string + "]";
    }

    /**
     * 获取SDCARD Size
     * @return
     */
    public static long getAvailaleSize() {
        File path = Environment.getExternalStorageDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSize();
        long availableBlocks = stat.getAvailableBlocks();
        return availableBlocks * blockSize;
    }
}
